package com.cn.psys.jhfb.imp;

import java.io.*;
import java.math.BigDecimal;
import java.util.*;
import cn.hutool.core.util.StrUtil;
import com.cn.psys.system.entity.JhfbStu;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class Jhfb {
    public static void main(String[] args) {

        for(int i = 0;i<5000;i++){
            Map<String, List<JhfbStu>> class_map = dotask("班级",5,"1","1","/Users/zhuwei/Documents/test1.xls");

        int studentM_num = 0;
        int studentW_num = 0;
        Map<String,Integer> nation = new HashMap<>();
        List<BigDecimal> list = new ArrayList<>();
        for (String key : class_map.keySet()) {
            nation = new HashMap<>();
            BigDecimal all_score = new BigDecimal(0);
            List<JhfbStu> stu_tmp = class_map.get(key);
            studentM_num = 0;
            studentW_num = 0;
            for (JhfbStu tmp : stu_tmp) {
                all_score = all_score.add(new BigDecimal(tmp.getAllScore()));
                if ("男".equals(tmp.getSex().trim())) {
                    studentM_num++;
                } else {
                    studentW_num++;
                }
                if(nation.containsKey(tmp.getNation())){
                    nation.put(tmp.getNation(),nation.get(tmp.getNation())+1);
                }else{
                    nation.put(tmp.getNation(),1);
                }
            }
            list.add(all_score.divide(new BigDecimal(
                    stu_tmp.size()), 2, BigDecimal.ROUND_HALF_UP));
           /* System.out.println(key
                    + "的平均分是："
                    + String.valueOf(all_score.divide(new BigDecimal(
                    stu_tmp.size()), 2, BigDecimal.ROUND_HALF_UP))
                    + "; 男生人数：" + studentM_num + "  女生人数：" + studentW_num+"民族："+nation);*/
        }
        System.out.println("--------第"+i+"次计算");
            sortAbs(list);
            if(list.get(0).subtract(list.get(list.size()-1)).abs().compareTo(new BigDecimal(3))==-1){
              //  System.out.println(class_map);
                for (String key : class_map.keySet()) {
                    nation = new HashMap<>();
                    BigDecimal all_score = new BigDecimal(0);
                    List<JhfbStu> stu_tmp = class_map.get(key);
                    studentM_num = 0;
                    studentW_num = 0;
                    for (JhfbStu tmp : stu_tmp) {
                        all_score = all_score.add(new BigDecimal(tmp.getAllScore()));
                        if ("男".equals(tmp.getSex().trim())) {
                            studentM_num++;
                        } else {
                            studentW_num++;
                        }
                        if(nation.containsKey(tmp.getNation())){
                            nation.put(tmp.getNation(),nation.get(tmp.getNation())+1);
                        }else{
                            nation.put(tmp.getNation(),1);
                        }
                    }
            System.out.println(key
                    + "的平均分是："
                    + String.valueOf(all_score.divide(new BigDecimal(
                    stu_tmp.size()), 2, BigDecimal.ROUND_HALF_UP))
                    + "; 男生人数：" + studentM_num + "  女生人数：" + studentW_num+"民族："+nation);
                }

                break;
            }
        }
    }


    /**
     * 根据条件自动编班
     *
     * @param className
     * @param class_num
     * @param sexFlag
     * @param filePath
     * @return
     */
    public static Map<String, List<JhfbStu>> dotask(String className, int class_num, String sexFlag,String nationFlag, String filePath) {
        // 学生集合
        List<JhfbStu> list_stu_w = null;
        // 学生对象
        JhfbStu stu = null;
        Workbook workbook = null;
        Sheet sheet = null;
        Cell cell = null;

        BigDecimal ave_score = new BigDecimal(0);//总得平均分
        BigDecimal sex_ponit = new BigDecimal(0);//男生比例
       // BigDecimal ave_stus = new BigDecimal(0);//平均每个班级人数
        Map<String,Object> nationMap = new HashMap<>();//各民族所占比例

        Map<String, List<JhfbStu>> class_map = new HashMap<String, List<JhfbStu>>();
        try {
            workbook = readExcel(filePath);
            sheet = workbook.getSheetAt(0);
            int rowCount = sheet.getPhysicalNumberOfRows();
            list_stu_w = new ArrayList<JhfbStu>();
            String cellData = null;
            //获取第一行
            Row row = sheet.getRow(0);
            for (int i = 1; i < rowCount; i++) {
                row = sheet.getRow(i);
                if(row !=null){
                       // cellData = (String) getCellFormatValue(row.getCell(j));
                        stu = new JhfbStu();
                        stu = stuInfo(row, stu);
                }else{
                    break;
                }
                if(StrUtil.isNotBlank(stu.getAllScore())){
                    list_stu_w.add(stu);
                }
            }
          //  ave_stus = new BigDecimal(list_stu_w.size()).divide(new BigDecimal(class_num),2,BigDecimal.ROUND_HALF_UP);
            //计算总得品均分
            BigDecimal score = new BigDecimal(0);
            int boy = 0;
            for(JhfbStu tmp : list_stu_w){
                score = score.add(new BigDecimal(tmp.getAllScore()));
                if("男".equals(tmp.getSex())){
                    boy = boy+1;
                }
                if(StrUtil.isNotEmpty(tmp.getNation())){
                    if(nationMap.containsKey(tmp.getNation())){
                        nationMap.put(tmp.getNation(),(Integer)nationMap.get(tmp.getNation())+1);
                    }else{
                        nationMap.put(tmp.getNation(),1);
                    }
                }

            }
            //平均分
            ave_score = score.divide(new BigDecimal(list_stu_w.size()), 2, BigDecimal.ROUND_HALF_UP);
            //男生人数比例
            sex_ponit = new BigDecimal(boy).divide(new BigDecimal(list_stu_w.size()),2, BigDecimal.ROUND_HALF_UP);
            //每个民族人数的占比
            for (String key : nationMap.keySet()) {
                nationMap.put(key,new BigDecimal((Integer) nationMap.get(key)).divide(new BigDecimal(list_stu_w.size()),2, BigDecimal.ROUND_HALF_UP));
            }

            Random ran = new Random();
            List<JhfbStu> randomStu ;
            //创建class_num数量的班级,并且每个班级随机放入2个学生
            for (int i = 1; i <= class_num; i++) {
                randomStu = new ArrayList<>();
                int randomIndex = ran.nextInt(list_stu_w.size());
                randomStu.add(list_stu_w.get(randomIndex).setNewClass(i));
                list_stu_w.remove(randomIndex);
                randomIndex = ran.nextInt(list_stu_w.size());
                randomStu.add(list_stu_w.get(randomIndex).setNewClass(i));
                list_stu_w.remove(randomIndex);
                class_map.put(className + "-" + i, randomStu);
            }
            //按照与平均分的绝对值排序
            List<JhfbStu> list_stu= sortAbsList(list_stu_w,ave_score);

            //是否有遍历到满足条件的学生标识
            boolean has = false;
            //count计数，当count与班级数量相同时，count被重置成1
            int count = 0;
            //学生s型放入的标识，flag：从头到尾，true：从尾到头
            boolean flag = false;
            String classKey = null;
            String sexPoint = "";
            String nationPoint = "";
            List<JhfbStu> tmpList = null;
            //只要有学生就遍历
            while (list_stu.size()>0){
                //每次遍历重置has
                has = false;
                //每次遍历count+1
                count++;
                if(flag){
                    classKey = className+"-"+(class_num-count+1);
                }else{
                    classKey = className+"-"+count;
                }
                //性别开关
                if("0".equals(sexFlag)){
                    //关闭性别开关
                    sexPoint = "男,女";
                }else{
                    //打开性别开关，下个学生只有满足条件才会被选中
                    sexPoint = countSex((ArrayList<JhfbStu>)class_map.get(classKey),sex_ponit);
                }
                //民族开关
                if("0".equals(nationFlag)){
                    //关闭民族开关，下个学生民族不做限制，只要再nationMap的学生都行
                    for (String key : nationMap.keySet()){
                        nationPoint =nationPoint+key;
                    }
                }else{
                    //打开民族开关，下个学生只有满足条件才会被选中
                    nationPoint = countNation((ArrayList<JhfbStu>)class_map.get(classKey),nationMap);
                }
                for(int i = 0;i<list_stu.size();i++){
                    if(sexPoint.indexOf(list_stu.get(i).getSex())>-1 && nationPoint.indexOf(list_stu.get(i).getNation())>-1){
                            tmpList = class_map.get(classKey);
                            tmpList.add(list_stu.get(i).setNewClass(Integer.parseInt(classKey.split("-")[1])));
                            class_map.put(classKey,tmpList);
                            list_stu.remove(i);
                            has = true;
                            break;
                    }
                }
                if(!has){
                    //如果没有满足条件的，就放入剩余list的第一个对象
                    tmpList = class_map.get(classKey);
                    tmpList.add(list_stu.get(0).setNewClass(Integer.parseInt(classKey.split("-")[1])));
                    class_map.put(classKey,tmpList);
                    list_stu.remove(0);
                }

                if(count==class_num){
                    flag = !flag;
                    count=0;
                }
            }
            // 关闭它，否则会有内存泄露
            workbook.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return class_map;
    }

    //计算男生比例，判断下个学生放入的性别条件
    public static String countSex(ArrayList<JhfbStu> list,BigDecimal sex_ponit){
        String res ;
        BigDecimal count = new BigDecimal(0);
        for (JhfbStu tmp : list){
            if("男".equals(tmp.getSex())){
                count = count.add(new BigDecimal(1));
            }
        }
        if (count.divide(new BigDecimal(list.size()),2,BigDecimal.ROUND_HALF_UP).compareTo(sex_ponit)>0){
            res = "女";
        }else{
            res = "男";
        }
        return res;
    }

    //计算各民族比例,得出下个学生放入的民族条件
    public static String countNation(ArrayList<JhfbStu> list,Map<String,Object> nationMap){
        String res = "";
        BigDecimal count = new BigDecimal(0);
        for(String key:nationMap.keySet()){
            count = new BigDecimal(0);
            for(JhfbStu tmp : list){
                if(key.equals(tmp.getNation())){
                    count = count.add(new BigDecimal(1));
                }
            }
            BigDecimal tmp = count.divide(new BigDecimal(list.size()),2,BigDecimal.ROUND_HALF_UP);
            BigDecimal index = (BigDecimal) nationMap.get(key);
            if(tmp.compareTo(index)==-1){
                res = res + key + ",";
            }
        }
        return res;
    }

    /**
     * java对象的集合自定义排序
     *
     * @param list
     * @return
     */
    public static List<JhfbStu> sortList(List<JhfbStu> list) {

        Collections.sort(list, new Comparator<JhfbStu>() {
            @Override
            public int compare(JhfbStu obj1, JhfbStu obj2) {

                if (new BigDecimal(obj1.getAllScore()).compareTo(new BigDecimal(
                        obj2.getAllScore())) > 0) {
                    return -1;
                } else {
                    return 1;
                }
            }
        });
        return list;
    }

    /**
     * 根据list中元素的属性与一个常量差的绝对值，进行排序。越靠近常量，排序越靠前
     *
     * @param list
     * @return
     */
    public static List<JhfbStu> sortAbsList(List<JhfbStu> list,BigDecimal ave_score){
        List<JhfbStu> newList = new ArrayList<>();
        List<BigDecimal> abs = new ArrayList<>();
        for(JhfbStu tmp : list){
            abs.add(new BigDecimal(tmp.getAllScore()).subtract(ave_score).abs());
        }
        sortAbs(abs);
        List<BigDecimal> listTemp = new ArrayList();
        for(int i=0;i<abs.size();i++){
            if(!listTemp.contains(abs.get(i))){
                listTemp.add(abs.get(i));
            }
        }
        for(BigDecimal tmpBdcm : listTemp){
            for(JhfbStu tmp : list){
                if (new BigDecimal(tmp.getAllScore()).subtract(ave_score).abs().compareTo(tmpBdcm)==0){
                    newList.add(tmp);
                    //break;
                }
            }
        }
        return newList;
    }

    /**
     * 升序
     * @param list
     * @return
     */
    public static List<BigDecimal> sortAbs(List<BigDecimal> list) {

        Collections.sort(list, new Comparator<BigDecimal>() {
            @Override
            public int compare(BigDecimal obj1, BigDecimal obj2) {

                if (obj1.compareTo(obj2) > 0) {
                    return 1;
                } else {
                    return -1;
                }
            }
        });
        return list;
    }


    /**
     * 将cell内容设置到学生实例中，返回一个学生实例
     *
     * @param stu
     * @return
     */
    public static JhfbStu stuInfo(Row row, JhfbStu stu) {
        // 准考证号
        stu.setTicketNumber((String) getCellFormatValue(row.getCell(0)));
        // 姓名
        stu.setStuName((String) getCellFormatValue(row.getCell(1)));
        // 性别
        stu.setSex((String) getCellFormatValue(row.getCell(2)));
         // 证件号
        stu.setCardNum((String) getCellFormatValue(row.getCell(3)));
         // 民族
        stu.setNation((String) getCellFormatValue(row.getCell(4)));
        // 报名地州
        stu.setRepCity((String) getCellFormatValue(row.getCell(5)));
        // 毕业学校
        stu.setGraduateSchool((String) getCellFormatValue(row.getCell(6)));
         // 学籍号
        stu.setStuNumber((String) getCellFormatValue(row.getCell(7)));
        // 团员
        stu.setLeagueMembers((String) getCellFormatValue(row.getCell(8)));
        // 语文成绩
        stu.setLanguageScore((String) getCellFormatValue(row.getCell(9)));
        // 物理化学成绩
        stu.setPhyChemistryScore((String) getCellFormatValue(row.getCell(10)));
        // 数学成绩
        stu.setMathScore((String) getCellFormatValue(row.getCell(11)));
        // 道德与法制、历史成绩
        stu.setHisScore((String) getCellFormatValue(row.getCell(12)));
         // 外语成绩
        stu.setEnglishScore((String) getCellFormatValue(row.getCell(13)));
        // 总成绩（不含体育）
        stu.setAllScore((String) getCellFormatValue(row.getCell(14)));
        // 体育是否合格
        stu.setSportScore((String) getCellFormatValue(row.getCell(15)));
        return stu;
    }

    /**
     * 根据路径读取excel文件，返回一个可操作的excel对象
     * @param filePath
     * @return
     */
    public static Workbook readExcel(String filePath){
        Workbook wb = null;
        if(filePath==null){
            return null;
        }
        String extString = filePath.substring(filePath.lastIndexOf("."));
        InputStream is = null;
        try {
            is = new FileInputStream(filePath);
            if(".xls".equals(extString)){
                return wb = new HSSFWorkbook(is);
            }else if(".xlsx".equals(extString)){
                return wb = new XSSFWorkbook(is);
            }else{
                return wb = null;
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return wb;
    }

    /**
     * 读取cell的内容
     * @param cell
     * @return
     */
    public static Object getCellFormatValue(Cell cell){
        Object cellValue = null;
        if(cell!=null){
            //判断cell类型
            switch(cell.getCellType()){
                case Cell.CELL_TYPE_NUMERIC:{
                    cellValue = String.valueOf(cell.getNumericCellValue());
                    break;
                }
                case Cell.CELL_TYPE_FORMULA:{
                    //判断cell是否为日期格式
                    if(DateUtil.isCellDateFormatted(cell)){
                        //转换为日期格式YYYY-mm-dd
                        cellValue = cell.getDateCellValue();
                    }else{
                        //数字
                        cellValue = String.valueOf(cell.getNumericCellValue());
                    }
                    break;
                }
                case Cell.CELL_TYPE_STRING:{
                    cellValue = cell.getRichStringCellValue().getString();
                    break;
                }
                default:
                    cellValue = "";
            }
        }else{
            cellValue = "";
        }
        return cellValue;
    }
}

